package top.hekun.study.core.visitor.method.simple;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;
import top.hekun.study.core.util.MyMethodVisitor5Util;

import static org.objectweb.asm.Opcodes.*;

/**
 * @Author: 贺坤
 * @Date: 2023/5/10 10:16
 */
public class MyMethodVisitor7 extends AdviceAdapter {
    private String thisClassName = this.getClass().getSimpleName();

    protected MyMethodVisitor7(int api, MethodVisitor methodVisitor, String descriptor, int access, String name) {
        super(api, methodVisitor, access, name, descriptor);
    }

    /**
     * 方法开始的时候调用
     */
    @Override
    protected void onMethodEnter() {
        System.out.println(thisClassName + ":onMethodEnter");
        // 获取方法参数
        Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
        // 确定获取参数起始位
        int slotIndex = ((methodAccess & Opcodes.ACC_STATIC) != 0) ? 0 : 1;
        for (int i = 0; i < argumentTypes.length; ) {
            Type type = argumentTypes[i];
            // 获取类型
            int sort = type.getSort();
            // 获取长度
            int size = type.getSize();
            // 获取描述符
            String descriptor = type.getDescriptor();
            // 获取对应类型的操作码  , ILOAD 为int 类型加载的操作码,getOpcode会自动转换
            int opcode = type.getOpcode(ILOAD);
            visitVarInsn(opcode, slotIndex + i);
            // 调用用静态方法
            visitMethodInsn(INVOKESTATIC, Type.getType(MyMethodVisitor5Util.class).getInternalName(), "parameterPrintln", Type.getMethodDescriptor(Type.VOID_TYPE, type), false);
            // 移动标志位, 有的数据类型 如Long  占用2位长度
            i += size;
        }
        super.onMethodEnter();
    }

    /**
     * 方法结束的时候调用
     *
     * @param opcode
     */
    @Override
    protected void onMethodExit(int opcode) {
        // 当 opcode =RETURN 的是 执行  return null;
        if (opcode == RETURN) {
            visitInsn(ACONST_NULL);
        } else if (opcode == ATHROW) {
            // 异常情况
            visitLdcInsn("异常退出");
        } else {
            // 获取返回类型
            Type returnType = Type.getReturnType(this.methodDesc);
            //  复制对象
            visitInsn(returnType.getOpcode(DUP));
            // 对象类型以及 数组等特殊类型可能需要单独处理
            visitMethodInsn(INVOKESTATIC, Type.getType(MyMethodVisitor5Util.class).getInternalName(), "returnPrintln", Type.getMethodDescriptor(Type.VOID_TYPE, returnType), false);

        }
        super.onMethodExit(opcode);
    }


}
